#pragma once

#include <stx/core/net.hpp>

inline namespace stx
{
using ShellInputter    = std::function<Future<Status>(FileDescriptor)>;
using CbOnOutputBuffer = std::function<Future<Status>(bool const, Buffer&)>;
using CbOnOutputString = std::function<Future<Status>(bool const, std::string)>;

struct ShellResult final
{
    Status                  status = 0;
    std::deque<std::string> cout;
    std::deque<std::string> cerr;
};

struct ShellRawResult final
{
    Status             status = 0;
    std::deque<Buffer> cout;
    std::deque<Buffer> cerr;
};

[[nodiscard]] std::string tos(ShellResult const& shr);
[[nodiscard]] std::string tos(ShellRawResult const& srr);

[[nodiscard]] Future<Status> shell(StringView const             sv_cmd,
                                   CbOnOutputBuffer             fn_on_output,
                                   Duration const               dur_timeout,
                                   std::optional<ShellInputter> opt_fn_cin);

[[nodiscard]] Future<Status> shell(StringView const sv_cmd,
                                   CbOnOutputBuffer fn_on_output,
                                   Duration const   dur_timeout);

[[nodiscard]] Future<Status> shell(StringView const             sv_cmd,
                                   CbOnOutputBuffer             fn_on_output,
                                   std::optional<ShellInputter> opt_fn_cin);

[[nodiscard]] Future<Status> shell(StringView const sv_cmd,
                                   CbOnOutputBuffer fn_on_output);

[[nodiscard]] Future<Status> shell(StringView const             sv_cmd,
                                   CbOnOutputString             fn_on_output,
                                   Duration const               dur_timeout,
                                   std::optional<ShellInputter> opt_fn_cin);

[[nodiscard]] Future<Status> shell(StringView const             sv_cmd,
                                   CbOnOutputString             fn_on_output,
                                   std::optional<ShellInputter> opt_fn_cin);

[[nodiscard]] Future<Status> shell(StringView const sv_cmd,
                                   CbOnOutputString fn_on_output,
                                   Duration const   dur_timeout);

[[nodiscard]] Future<Status> shell(StringView const sv_cmd,
                                   CbOnOutputString fn_on_output);

[[nodiscard]] Future<ShellResult>
shell(StringView const sv_cmd, Duration const dur_timeout, MemView mv_cin);

[[nodiscard]] Future<ShellResult> shell(StringView const sv_cmd,
                                        Duration const   dur_timeout);

[[nodiscard]] Future<ShellResult> shell(StringView const sv_cmd,
                                        MemView const    mv_cin);

[[nodiscard]] Future<ShellResult> shell(StringView const sv_cmd);

[[nodiscard]] Future<ShellRawResult> shellRaw(StringView const sv_cmd,
                                              Duration const   dur_timeout,
                                              MemView const    mv_cin);

[[nodiscard]] Future<ShellRawResult> shellRaw(StringView const sv_cmd,
                                              Duration const   dur_timeout);

[[nodiscard]] Future<ShellRawResult> shellRaw(StringView const sv_cmd,
                                              MemView const    mv_cin);

[[nodiscard]] Future<ShellRawResult> shellRaw(StringView const sv_cmd);
} // namespace stx